///////////////////////////////////////////////////////////////////////////////

#ifndef _SERVERBATTLEFIELD_H_
#include "serverbattlefield.h"
#endif

#ifndef _PHYSICS_H_
#include "physics.h"
#endif

#ifndef _SHAPESFACTORY_H_
#include "shapesfactory.h"
#endif

///////////////////////////////////////////////////////////////////////////////


ServerBattlefield::ServerBattlefield()
: m_PhysicsEngine( Physics::GetPhysicalEngine() ),
  m_BorderWall(0)
{
    // Add border wall to physical engine
    m_BorderWall.SetPosition( PE::Point(320, 240) );
    m_PhysicsEngine->AddStableObject(m_BorderWall);
}


///////////////////////////////////////////////////////////////////////////////


ServerBattlefield::~ServerBattlefield()
{
}


///////////////////////////////////////////////////////////////////////////////


void ServerBattlefield::Update( size_t _dt )
{
    ProcessUserInput(_dt);
    UpdatePhysics(_dt);
}


///////////////////////////////////////////////////////////////////////////////


void ServerBattlefield::ProcessUserInput( size_t _dt )
{
    // Process shooting
    for (SPlayersByIDs::iterator it = m_SPlayersByIDs.begin(); it != m_SPlayersByIDs.end(); ++it )
    {
        SPlayer& player = it->second;
        player.ProcessInput(_dt);

        if ( player.CanShoot(_dt) )
        {
            m_Bullets.push_back( player.Shoot() );
            m_PhysicsEngine->AddMovingObject( m_Bullets.back() );
        }
    }
}


///////////////////////////////////////////////////////////////////////////////


void ServerBattlefield::UpdatePhysics( size_t _dt )
{
    m_PhysicsEngine->Update(_dt);
}


///////////////////////////////////////////////////////////////////////////////


void ServerBattlefield::AddPlayer( int _ID )
{
    // Add new player
    SPlayer newPlayer(_ID, 100, SWeapon(500) );
    SPlayer& player = m_SPlayersByIDs.insert( std::make_pair(_ID, newPlayer) ).first->second;

    // Adjust it's position
    player.SetPosition( PE::Point(300, 100) );

    // Add it to physics
    m_PhysicsEngine->AddMovingObject(player);
}


///////////////////////////////////////////////////////////////////////////////


void ServerBattlefield::SetClientInput( int _clientID,
                                        const ClientInput& _input,
                                        size_t _creationTime )
{
    GetMappedValue(m_SPlayersByIDs, _clientID).SetClientInput(_input, _creationTime);
}


////////////////////////////////////////////////////////////////////////////////


ServerState ServerBattlefield::GetState() const
{
    PlayersList players;
    for (SPlayersByIDs::const_iterator it = m_SPlayersByIDs.begin(); it != m_SPlayersByIDs.end(); ++it )
    {
        const SPlayer& sPlayer = it->second;
        Player player( sPlayer.GetID() );
        Point position( static_cast<float>(sPlayer.GetPosition().x),
                        static_cast<float>(sPlayer.GetPosition().y) );
        player.SetPosition(position);
        players.push_back(player);
    }

    BulletsList bullets;
    for (SBulletsList::const_iterator it = m_Bullets.begin(); it != m_Bullets.end(); ++it)
    {
        const SBullet& sBullet = *it;
        Bullet bullet( sBullet.GetID() );
        Point position( static_cast<float>(sBullet.GetPosition().x),
                        static_cast<float>(sBullet.GetPosition().y) );
        bullet.SetPosition(position);
        bullets.push_back(bullet);
    }

    return ServerState( players, bullets, WallsList() );
}


////////////////////////////////////////////////////////////////////////////////


void ServerBattlefield::RemovePlayer( int _ID )
{
    // Get player by ID
    SPlayer& player = GetMappedValue(m_SPlayersByIDs, _ID);

    // Remove it from physics
    m_PhysicsEngine->DeleteObject(player);

    // Remove it from engine
    m_SPlayersByIDs.erase(_ID);
}


////////////////////////////////////////////////////////////////////////////////


bool ServerBattlefield::HasPlayer( int _playerID ) const
{
    return ContainsKey(m_SPlayersByIDs, _playerID);
}


////////////////////////////////////////////////////////////////////////////////
